package com.beiding.render;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//模板编译器
public class TemplateCompiler {


    private static final RenderTime defaultRenderTime = new RenderTime((relative, path) -> null, (relative, plugins) -> null, (relative, path) -> null, (relative, path) -> null, Collections.singletonList(new RenderFilter() {
        @Override
        public void filter(This _this, NextFilterHolder nextFilterHolder) {
            _this.render();
        }

        @Override
        public int order() {
            return Integer.MAX_VALUE;
        }
    }));


    private RenderTime renderTime = defaultRenderTime;

    //区块标签开始结束名称
    private String blockTagName = "bk";

    //渲染标签名称
    private String renderTagName = "rd";

    //根节点名称
    private String rootTagName = "tp";

    private String annotationSymbol;

    /**
     * 设置渲染运行时
     * @param renderTime
     */

    public void setRenderTime(RenderTime renderTime) {
        this.renderTime = renderTime;
    }

    //解析器
    private ULabel uRoot = new ULabel(rootTagName);
    private ULabel uBlock = new ULabel(blockTagName);
    private ULabel uRender = new ULabel(renderTagName);

    private String annotationPre;
    private String annotationPost;

    {
        setAnnotationSymbol("#");
    }

    public Template compile(InputStream inputStream, String coordinate) throws IOException {
        String s = FileUtils.readInputStreamAsString(inputStream);
        return compile(s, coordinate);
    }


    /**
     * 编译一个模板
     *
     * @param text 待编译的文本
     * @param coordinate 当前模板的相对坐标
     *                   第二个参数用来定义当前模板的坐标,使用该坐标可用来进行外部模板的查找或者外部插件的查找
     *
     * @return
     */
    public Template compile(String text, String coordinate) {

        text = ContentUtils.removeAnnotation(text, annotationPre, annotationPost);

        //编译文本不能为空
        if (ContentUtils.isEmpty(text)) {
            throw new RuntimeException("文本不能为空");
        }

        //解析根节点
        List<Pair> pairs = uRoot.parsePairs(text);

        String t = uRoot.replaceHolder(text, pairs);

        //文本替换

        if (pairs.size() != 1 || !pairs.get(0).holder.equals(t.trim())) {
            throw new RuntimeException("模板中有且仅能有一个根节点");
        }


        //TODO 根节点使用手动创建,需要具备传递性
        Label root = uRoot.toLabel(pairs, "root").get(0);


        //根节点的模板
        root.template = innerCompile(root.body, coordinate);

        TemplateImpl template = new TemplateImpl();
        template.setRoot(root);
        template.setRenderTime(root.template.getRenderTime());
        template.setCoordinate(coordinate);


        template.setText(t);
        //TODO 将root内的文本处理成模板

        //
        return template;
    }

    private TemplateImpl innerCompile(String text, String coordinate) {

        //解析所有的区块
        List<Pair> pairs = uBlock.parsePairs(text);
        Map<String, TemplateImpl> innerTpMap = new HashMap<>();
        RenderTime renderTime = new RenderTime(new InnerAbleTemplateFinder(this.renderTime.getTemplateFinder(), innerTpMap), this.renderTime.getPluginFinder(), this.renderTime.getHandlerFinder(), this.renderTime.getResourceFinder(), this.renderTime.getFilters());
        return TemplateCreator.create(text, pairs, uBlock, uRender, coordinate, renderTime, innerTpMap);

    }


    public void setBlockTagName(String blockTagName) {
        this.blockTagName = blockTagName;
        this.uBlock.setTagName(blockTagName);
    }

    public void setRenderTagName(String renderTagName) {
        this.renderTagName = renderTagName;
        this.uRender.setTagName(renderTagName);

    }

    public String getBlockTagName() {
        return blockTagName;
    }

    public void setAnnotationSymbol(String annotationSymbol) {
        annotationSymbol.getClass();
        this.annotationSymbol = annotationSymbol;
        this.annotationPre = "<!--" + annotationSymbol;
        this.annotationPost = annotationSymbol + "-->";
    }

    public String getAnnotationSymbol() {
        return annotationSymbol;
    }

    public String getRenderTagName() {
        return renderTagName;
    }

}

